Introducao

É inquestionável a importância de previsão para a tomada de decisão para qualquer que seja a área. Desde serviços meteorológicos que estamos mais familiarisados assistindo na TV ao mundo dos negócios (cadeia de suprimentos, vendas, finanças, etc). Por isso, vários são esforços em desenvolver modelos que assegurem resultados aceitáveis em termos de precisão. Foi com esse intuíto que Facebook’s Core Data Science team desenvolveu o prophet package uma ferramenta open-source para a previsão de dados de séries temporais. Nas suas próprias palavras “make it easier for experts and non-experts to make high quality forecasts that keep up with demand”, https://facebook.github.io/prophet/.

No presente trabalho, vamos nos focar em como aplicar o prophet package, para previsão de demanda para os próximos 12 meses com base em dados históricos (pedidos dos clientes) de 2011 a 2015 referente à bikes dataset, htps://www.business-science.io/business/2016/07/12/orderSimulatoR.html. Aqui, vamos também mostrar como usar funções (function) para limpeza e maior compreensão do código assim como para a sua reusabilidade.

Devido a sua simplicidade, precisão e rápidez escolhemos essa técnica para demonstrar a sua aplicação nos negócios usando R. Portanto, nos próximos trabalhamos vamos avaliar a sua precisão comparando-a com outras abordagens tais como ARIMA, XGBoost, etc.

Aplicação do prophet package

A previsão é geralmente considerada uma progressão natural dos Reports. Os Reports nos ajudam a responder, o que aconteceu? A previsão ajuda a responder à próxima pergunta lógica, o que acontecerá?

Vamos apresentar como usar o prophet package em R para resolver problemas comuns de uma forma simples. Portanto, vamos nos focar nos seguintes passos:
1. Exploração e preparação dos dados;
2. Transformação dos dados;
3. Previsão;
4. Transformação inversa dos dados.

Exploração e preparação dos dados

O prophet package trabalha melhor com dados diários, de preferência com dados históricos com um horizonte temporal de pelo menos 01 ano. Contudo, podem ser feitas previsões semanais ou mensais, como será demonstrado no presente trabalho.

Primeiro, precisamos de instalar o prophet package:

# R
library(prophet)
## Warning: package 'prophet' was built under R version 3.6.1
## Loading required package: Rcpp
## Loading required package: rlang
## Warning: package 'rlang' was built under R version 3.6.1
## Registered S3 methods overwritten by 'ggplot2':
##   method         from 
##   [.quosures     rlang
##   c.quosures     rlang
##   print.quosures rlang
library(highcharter)
## Warning: package 'highcharter' was built under R version 3.6.1
## Registered S3 method overwritten by 'xts':
##   method     from
##   as.zoo.xts zoo
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## Highcharts (www.highcharts.com) is a Highsoft software product which is
## not free for commercial and Governmental use

De seguida, faz-se a leitura dos dados a partir de ficheiros ou extraindo de uma base de dados via SQL. Aqui o mais importante é seleccionar duas (02) variáveis e renomear para ds e y, e estas devem ser do tipo datetime e numérica respectivamente. A variável ds serve de referência ou índice.

Para o nosso caso, trata-se de vendas mensais de bicicletas extraidas da nossa fonte de dados bike dataset.

monthly_sales %>% head() 
## # A tibble: 6 x 2
##   Month       Amount
##   <date>       <dbl>
## 1 2011-01-01  483015
## 2 2011-02-01 1162075
## 3 2011-03-01  659975
## 4 2011-04-01 1827140
## 5 2011-05-01  844170
## 6 2011-06-01 1413445
# renomear as variaveis para 'ds' e 'y'
df <- monthly_sales
colnames(df) <- c("ds", "y")

Transformação dos dados

Existem vários métodos para transformação de dados. Mas essa matéria está fora de escopo do presente trabalho, por isso não vamos dedicar atenção sobre está matéria. Contudo, recomendo o seguinte website, https://www.statisticshowto.datasciencecentral.com/box-cox-transformation/.

Para o presente caso, usamos a função logarítmica para transformar os dados.

df$y <- log(df$y)

Previsão

O prophet function usa dados históricos do dataframe para fazer a previsão. A coluna ds contém as datas pelos quais são feitas as predições.

# R
m <- prophet(df)
## Disabling weekly seasonality. Run prophet with weekly.seasonality=TRUE to override this.
## Disabling daily seasonality. Run prophet with daily.seasonality=TRUE to override this.

A make_future_dataframe function tem como input o objecto modelo m e o número de periodos por prever bem como a dimensão temporal, dia, mês ou ano e produz um apropriado dataframe. Por defeito, este dataframe inclui as datas históricas que podem servir para avaliação da amostra.

# R
future <- make_future_dataframe(m, periods = 12, freq = "month")
tail(future) 
##            ds
## 67 2016-07-01
## 68 2016-08-01
## 69 2016-09-01
## 70 2016-10-01
## 71 2016-11-01
## 72 2016-12-01

Como em muitos modelos de predição em R, usamos a função predict para obter os valores preditos. O objecto forecast é um dataframe com a coluna yhat conténdo os valores previstos. Adicionalmente, existem colunas que mostram o intervalo de confiança e a componente sazonal.

# R
forecast <- predict(m, future)
tail(forecast[c('ds', 'yhat', 'yhat_lower', 'yhat_upper')]) 
##            ds     yhat yhat_lower yhat_upper
## 67 2016-07-01 14.52701   14.23467   14.82830
## 68 2016-08-01 14.28357   13.97667   14.57092
## 69 2016-09-01 14.13654   13.80591   14.44208
## 70 2016-10-01 13.60182   13.27421   13.90634
## 71 2016-11-01 13.51939   13.22201   13.82688
## 72 2016-12-01 13.38242   13.07026   13.68128

Podemos usar a função genérica plot para visualizar os valores previstos passando os parâmetros m e forecast.

# R
plot(m, forecast)

Também podemos usar a função prophet_plot_components para visualizar a tendência, a sazonalidade semanal e anual.

# R
prophet_plot_components(m, forecast)

Criar uma função para retornar valores previstos

Um dos procedimentos recomendados para qualquer developer é a criação de funções para a reusabilidade e limpeza do código. Assim, para o nosso exemplo foi desenvolvida a seguinte função:

# apply function for forecasting -------------------------------------------

forecast_mode <- function(result_tbl, periods, freq){
    
    colnames(result_tbl) <- c("ds", "y")
    
    result_tbl$y <- log(result_tbl$y)
    
    
    m <- prophet(result_tbl)
    # m <- prophet(result_tbl, seasonality.mode = "multiplicative")
    
    future <- make_future_dataframe(m, periods = periods, freq = freq)
    
    forecast <- predict(m, future)
    
    forecast_tbl <- 
        forecast %>%
        select(ds, yhat, yhat_lower, yhat_upper)
    
    return (forecast_tbl)
}

Onde os parâmetro de entrada são:
- result_tbl: dataframe conténdo os dados originais;
- periods: periódo de previsão expressando o número de dias, semanas ou anos conforme o parâmetro freq;
- freq: periodicidade que pode variar entre “day ou d”, “week ou w” e “year ou y”.

E também, foi desenvolvida uma outra função para a visualização dos valores previstos (na unidade original) juntamente com os valores históricos.

# plot Forecast Demand ------------------------------------------------

plot_hc_forecasted <- function(original_tbl, forecast_tbl){
    
    colnames(original_tbl) <- c("x_var", "y_var")
    
    highchart(type = "stock") %>% 
        hc_add_series(data = original_tbl, 
                      type = "line", 
                      hcaes(x = x_var, y = y_var), 
                      name = "Actual") %>% 
        hc_add_series(data = forecast_tbl, 
                      type = "spline", 
                      hcaes(x = as.Date(ds), y = round(exp(yhat),0)), 
                      name = "Predicted",
                      id = "fit", # this is for link the arearange series to this one and have one legend
                      lineWidth = 1) %>% 
        hc_add_series(
            data = forecast_tbl,
            type = "arearange",
            hcaes(x = as.Date(ds), low = round(exp(yhat_lower),0), high = round(exp(yhat_upper),0)),
            name = "Range",
            linkedTo = "fit", # here we link the legends in one.
            color = hex_to_rgba("gray", 0.2),  # put a semi transparent color
            zIndex = -3 # this is for put the series in a back so the points are showed first
        )
    
}

Aplicando a função para retornar valores previstos

Vamos usar as funções criadas anteriormente para mostrar a sua aplicação.

original_tbl <- monthly_sales

forecast_tbl <- forecast_mode(original_tbl, periods = 12, freq = "month")
## Disabling weekly seasonality. Run prophet with weekly.seasonality=TRUE to override this.
## Disabling daily seasonality. Run prophet with daily.seasonality=TRUE to override this.
hc_out <- plot_hc_forecasted(original_tbl, forecast_tbl)
## Warning: `parse_quosure()` is deprecated as of rlang 0.2.0.
## Please use `parse_quo()` instead.
## This warning is displayed once per session.
hc_out %>% 
        hc_exporting(enabled = TRUE) %>% 
        hc_title(text = "Forecasting Monthly Revenue")

O gráfico acima ilustra o resultado final. Fácilmente, pode-se observar a região do intervalo de confiança de 95% onde se espera que os valores previsto caim dentro desse intervalo. Sugiro que usem a função para dados diários ou semanais bastando para tal mudar os parâmetros periods e freq.

Seria interessante avaliar o grau de precisão desse modelo, dividindo a série de dados em training e test e comparando-o com outras abordagens tais como ARIMA, XGBoost, etc. Mas isso será matéria do próximo trabalho.

Conclusão

O prophet package é um método fácil de usar e robusto com alto nível de precisão. Recomendo a sua aplicação no mundo dos negócios para a previsão de demanda. Criar uma função para reusabilidade e limpeza de código simplifica o processo de desenvolvimento de qualquer programa. No presente trabalho, ficou demonstrado essa simplicidade.

Em jeito de sugestão, encorajo-vos a aplicar esse procedimento com dados reais, pois vos asseguro que o mesmo foi testado com sucesso e está em produção com resultados satisfatórios. Para o efeito, tivemos que dividir os dados em training e test. Considerando dados de test os últimos 90 dias contando sempre da presente data, Sys.Date().

Referências

[1] Prophet: forecasting at scale; https://facebook.github.io/prophet/
[2] Forecasting with Prophet; https://towardsdatascience.com/forecasting-with-prophet-d50bbfe95f91
[3] Forecasting in Python with Prophet; https://mode.com/example-gallery/forecasting_prophet_python_cookbook/#box-cox-transform
[4] Generate Quick and Accurate Time Series Forecasts using Facebook’s Prophet (with Python & R codes); https://www.analyticsvidhya.com/blog/2018/05/generate-accurate-forecasts-facebook-prophet-python-r/
[5] Using Open Source Prophet Package to Make Future Predictions in R; https://towardsdatascience.com/using-open-source-prophet-package-to-make-future-predictions-in-r-ece585b73687